//-------------------------------------- 
// easy-riscv decode and issue
//--------------------------------------

module EASY_RISCV_IDU (
    input  wire         i_clk
,   input  wire         i_rst_n
,   input  wire         i_instr_vld_f1
,   input  wire [31:0]  i_dec_instr_f1
,   input  wire [31:0]  i_cur_pc_f1
,   input  wire         i_excp_pc_vld_f1
,   input  wire         i_excp_unaligned_access_e0
,   input  wire [2:0]   i_excp_mask_config
,   input  wire         i_rf_wr_vld_e0
,   input  wire [4:0]   i_rf_wr_index_e0
,   input  wire [31:0]  i_rf_wr_data_e0
,   input  wire         i_rf_wr_vld_c0
,   input  wire [4:0]   i_rf_wr_index_c0
,   input  wire [31:0]  i_rf_wr_data_c0
,   output wire         o_instr_vld_d0
,   output wire [31:0]  o_cur_pc_d0
,   output wire [5:0]   o_what_is_instr_d0
,   output wire [4:0]   o_rd_index_d0
,   output reg  [31:0]  o_rs1_data_d0
,   output reg  [31:0]  o_rs2_data_d0
,   output wire [4:0]   o_shamt_d0
,   output wire [31:0]  o_imm_data_d0
,   output reg  [2:0]   o_excps_d1
,   output reg  [31:0]  o_excps_pc_d1
,   output wire         o_fetch_stall_d0
);

//--------------------------------------
wire            excp_instr_vld_d0       ;
reg  [2:0]      excp_mask_config_ff[1:0];
reg  [2:0]      excp_mask_config        ;
wire            excp_vld_d0             ;
wire            excp_vld_hold           ;

reg  [5:0]      what_is_instr_d0        ;
wire [6:0]      opcode_d0               ;
wire [2:0]      funct3_d0               ;
reg  [31:0]     imm_data_d0             ;

wire [4:0]      rs1_index_d0            ;
wire [4:0]      rs2_index_d0            ;
reg  [31:0]     gpr_x[31:0]             ;

//-------------------------------------- 
// easy-riscv decode
//--------------------------------------
assign opcode_d0    = i_dec_instr_f1[6:0]   ;
assign funct3_d0    = i_dec_instr_f1[14:12] ;

always @(*) begin
    case (opcode_d0)
        7'b0110111: what_is_instr_d0 = `RISCV_LUI   ;
        7'b0010011: begin
                    case(funct3_d0)
                        3'b000:  what_is_instr_d0 = `RISCV_ADDI;
                        default: what_is_instr_d0 = `RISCV_ILLEG_INSTR;
                    endcase
                end
        default:    what_is_instr_d0 = `RISCV_ILLEG_INSTR;
    endcase
end

always @(*) begin
    case(what_is_instr_d0)
        `RISCV_LUI   : imm_data_d0 = {i_dec_instr_f1[31:12], 12'b0};
        `RISCV_ADDI  : imm_data_d0 = {{21{i_dec_instr_f1[31]}}, i_dec_instr_f1[30:20]};
        default      : imm_data_d0 = 32'b0;
    endcase
end

//-------------------------------------- 
// easy-riscv exception
//--------------------------------------
assign excp_instr_vld_d0   = i_instr_vld_f1 & (what_is_instr_d0 == `RISCV_ILLEG_INSTR);

always @(posedge i_clk or negedge i_rst_n) begin
    if (i_rst_n == 1'b0) begin
        for (integer i=0; i<2; i=i+1) begin
            excp_mask_config_ff[i] <= 3'b0;
        end
    end
    else begin
        for (integer i=0; i<2; i=i+1) begin
            if (i == 0) begin
                excp_mask_config_ff[i] <= i_excp_mask_config;
            end
            else begin
                excp_mask_config_ff[i] <= excp_mask_config_ff[i-1];
            end
        end
    end
end
assign excp_mask_config = excp_mask_config_ff[1];

always @(posedge i_clk or negedge i_rst_n) begin
    if (i_rst_n == 1'b0) begin
        o_excps_d1      <= 3'b0 ;
        o_excps_pc_d1   <= 32'b0;
    end
    else if (i_excp_unaligned_access_e0 && (!excp_mask_config[2])) begin
        o_excps_d1[2]   <= 1'b1 ;
        o_excps_pc_d1   <= i_cur_pc_f1  ;
    end
    else if (i_excp_pc_vld_f1 && (!excp_mask_config[1])) begin
        o_excps_d1[1] <= 1'b1       ;
        o_excps_pc_d1 <= i_cur_pc_f1;
    end
    else if (excp_instr_vld_d0 && (!excp_mask_config[0])) begin
        o_excps_d1[0] <= 1'b1       ;
        o_excps_pc_d1 <= i_cur_pc_f1;
    end
end

assign excp_vld_d0   = (i_excp_unaligned_access_e0 & (~excp_mask_config[2])) | (i_excp_pc_vld_f1 & (~excp_mask_config[1])) | (excp_instr_vld_d0 & (~excp_mask_config[0]));
assign excp_vld_hold = excp_vld_d0 | (|o_excps_d1);

//-------------------------------------- 
// easy-riscv rf 
//--------------------------------------
always @(posedge i_clk or negedge i_rst_n) begin
    if (i_rst_n == 1'b0) begin
        for (integer i=0; i<32; i=i+1) begin
            gpr_x[i] <= 32'b0;
        end
    end
    else begin
	    if ((i_rf_wr_vld_e0 == 1'b1) && (i_rf_wr_index_e0 != 5'b0))
	        gpr_x[i_rf_wr_index_e0] <= i_rf_wr_data_e0;
        else if ((i_rf_wr_vld_c0 == 1'b1) && (i_rf_wr_index_c0 != 5'b0))
            gpr_x[i_rf_wr_index_c0] <= i_rf_wr_data_c0;
    end
end

always @(*) begin
    o_rs1_data_d0 = gpr_x[rs1_index_d0];
end

always @(*) begin
    o_rs2_data_d0 = gpr_x[rs2_index_d0];
end

assign o_fetch_stall_d0   = excp_vld_hold;

assign o_instr_vld_d0     = i_instr_vld_f1 & (~o_fetch_stall_d0);

assign o_cur_pc_d0        = i_cur_pc_f1;
assign o_what_is_instr_d0 = what_is_instr_d0;
assign rs1_index_d0       = i_dec_instr_f1[19:15];
assign rs2_index_d0       = i_dec_instr_f1[24:20];
assign o_rd_index_d0      = i_dec_instr_f1[11:7];
assign o_shamt_d0         = i_dec_instr_f1[24:20]; 
assign o_imm_data_d0      = imm_data_d0;

endmodule

